﻿#define _CRT_SECURE_NO_WARNINGS 1
#include "Minesweeping.h"

// 初始化棋盘
void init_board(int** board, int row, int col) {
	assert(board);
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++) {
		for (j = 0; j < col; j++) {
			board[i][j] = -1;
		}
	}
}

// 布置雷到棋盘,我们用-2表示雷
void set_mines(int** board, int row, int col, int mines_count) {
	assert(board);
	srand((unsigned int)time(NULL));
	int i = 0;
	int j = 0;
	while (mines_count) {
		i = (rand() % row);
		j = (rand() % col);
		if (board[i][j] == -1) {
			board[i][j] = -2;
			mines_count--;
		}
	}
}

// 打印坐标的函数
void print_coord(int i) {
	switch (i) {
	case 0:
		printf("⑴");
		break;
	case 1:
		printf("⑵");
		break;
	case 2:
		printf("⑶");
		break;
	case 3:
		printf("⑷");
		break;
	case 4:
		printf("⑸");
		break;
	case 5:
		printf("⑹");
		break;
	case 6:
		printf("⑺");
		break;
	case 7:
		printf("⑻");
		break;
	case 8:
		printf("⑼");
		break;
	case 9:
		printf("⑽");
		break;
	case 10:
		printf("⑾");
		break;
	case 11:
		printf("⑿");
		break;
	case 12:
		printf("⒀");
		break;
	case 13:
		printf("⒁");
		break;
	case 14:
		printf("⒂");
		break;
	case 15:
		printf("⒃");
		break;
	case 16:
		printf("⒄");
		break;
	case 17:
		printf("⒅");
		break;
	case 18:
		printf("⒆");
		break;
	case 19:
		printf("⒇");
		break;
	default:
		break;
	}
}

// 打印棋盘
// 参数flag表示的是打印的状态，0表示正常打印，1表示胜利时的打印，-1则表示被炸死时的打印
void print(int** board, int row, int col, int flag) {
	assert(board);
	// 坐标数组，用于打印
	int i = 0;
	int j = 0;
	// 打印边界(都是为了美观，其实可以忽略)
	for (i = 0; i < col + 2; i++) {
		if (0 == i) {
			printf(" ");
		}
		printf("__");
	}
	printf("\n");
	// 先打印列坐标
	for (i = 0; i < col; i++) {
		if (0 == i) {
			printf("|");
			printf("◤");
		}
		print_coord(i);
		if (col - 1 == i) {
			printf("◥");
			printf("|");
		}
	}
	printf("\n");
	// 打印棋盘内容与行坐标
	for (i = 0; i < row; i++) {
		printf("|");
		print_coord(i); // 首先打印上一个纵坐标
		for (j = 0; j < col; j++) {
			if (board[i][j] == -1) {
				printf("■");
			}
			else if (board[i][j] == -2) {
				if (0 == flag) {
					printf("■");
				}
				else if (1 == flag) {
					printf("★");
				}
				else {
					printf("※");
				}
			}
			else if (board[i][j] == 0) {
				printf("□");
			}
			else {
				printf("%2d", board[i][j]);
			}
		}
		print_coord(i); // 后面再跟上一个纵坐标
		printf("|");
		printf("\n");
	}
	// 最底端也打印一排坐标
	for (i = 0; i < col; i++) {
		if (0 == i) {
			printf("|");
			printf("◣");
		}
		print_coord(i);
		if (col - 1 == i) {
			printf("◢");
			printf("|");
		}
	}
	printf("\n");
	// 打印边界
	for (i = 0; i < col + 2; i++) {
		if (0 == i) {
			printf(" ");
		}
		printf("￣");
	}
	printf("\n");
}

// 统计坐标周围有多少个雷
void count_mines(int** board, int row, int col, int x, int y) {
	assert(board);
	int count = 0;
	int i = 0;
	int j = 0;
	// 开始计算雷数
	for (i = -1; i <= 1; i++) {
		for (j = -1; j <= 1; j++) {
			int X = x + i;
			int Y = y + j;
			if ((X < 0 || X > row - 1) || (Y < 0 || Y > col - 1)) { // 判断坐标的有效性
				continue;
			}
			if (i == 0 && j == 0) {
				continue;
			}
			if (-2 == board[X][Y]) {
				count++;
			}
		}
	}
	board[x][y] = count;
	if (0 == count) { // 当count等于0时，就要开始递归。
		// 开始递归
		for (i = -1; i <= 1; i++) {
			for (j = -1; j <= 1; j++) {
				int X = x + i;
				int Y = y + j;
				if ((X < 0 || X > row - 1) || (Y < 0 || Y > col - 1)) { // 判断坐标的有效性
					continue;
				}
				if (i == 0 && j == 0) {
					continue;
				}
				if (-1 == board[X][Y]) {
					count_mines(board, row, col, X, Y);
				}
			}
		}
	}
}


// 排查雷
void sweep_mines(int** board, int row, int col) {
	assert(board);
	int i = 0;
	int j = 0;
	while (1) {
		printf("请输入你要排查的坐标(i,j) :>");
		scanf("%d %d", &i, &j);
		if ((i < 1 || i > row) || (j < 1 || j > col)) {
			printf("输入的坐标非法，请重新输入……\n");
		}
		else if (board[i - 1][j - 1] == -2) {
			printf("  ________________________\n");
			printf(" |**********(>_<)*********|\n");
			printf(" |***很遗憾,你被炸死了!***|\n");
			printf("  ￣￣￣￣￣￣￣￣￣￣￣￣\n");

			print(board, row, col, -1);
			system("pause"); // 让程序先暂停好查看结果
			printf("正在返回主菜单……\n");
			Sleep(3000);
			system("cls");
			return;
		}
		else if (board[i - 1][j - 1] == -1) {
			// 统计坐标周围有多少个雷
			count_mines(board, row, col, i - 1, j - 1);
			if (is_wins(board, row, col)) {
				printf("  ____________________________________\n");
				printf(" |★★★★★★★(*^O^*)★★★★★★★ |\n");
				printf(" |★★★恭喜你,排雷成功!太棒了!★★★ |\n");
				printf("  ￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣￣\n");
				print(board, row, col, 1);
				system("pause");
				printf("正在返回主菜单……\n");
				Sleep(3000);
				system("cls");
				return;
			}
			else {
				print(board, row, col, 0);
			}
		}
		else {
			printf("该坐标已被排查过，请重新输入……\n");
		}
	}
}

// 判断游戏是否胜利，判断是否胜利的思路很简单，棋盘中再也找不到值为-1的坐标时候，游戏就胜利
// 胜利返回1，否则返回0
int is_wins(int** board, int row, int col) {
	assert(board);
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++) {
		for (j = 0; j < col; j++) {
			if (-1 == board[i][j]) {
				return 0;
			}
		}
	}
	return 1;
}